#include "SkyBox.h"
#include "Engine.h"
#include "Camera.h"
#include "GameState.h"

#define SKYBOX_RES 20

void SkyBox::SetTextures(   LPDIRECT3DTEXTURE9 floor, 
    LPDIRECT3DTEXTURE9 top, 
    LPDIRECT3DTEXTURE9 side0, 
    LPDIRECT3DTEXTURE9 side1, 
    LPDIRECT3DTEXTURE9 side2, 
    LPDIRECT3DTEXTURE9 side3 )
{
    m_texture[0] = floor;
    m_texture[1] = top;
    m_texture[2] = side0;
    m_texture[3] = side1;
    m_texture[4] = side2;
    m_texture[5] = side3;
}
void SkyBox::ShutDown()
{
    for(int i = 0; i < 6; ++i)
    {
        if(m_vBuffer[i])
            m_vBuffer[i]->Release();
    }
}
void SkyBox::InitializeDome(float posX, float posY, float posZ, int radius)
{
    m_scale[0] = m_scale[1] = m_scale[2] = radius;
    m_pos[0] = posX; m_pos[1] = posY; m_pos[2] = posZ;
    int numX = SKYBOX_RES; int numY = SKYBOX_RES;
    int numTris = ((numX * 2) - 2) * (numY - 1);
    m_numVerts = numTris * 3;
    for(int i = 0; i < 6; ++i)
        TEST(Engine::Instance()->GetDevice()->CreateVertexBuffer( m_numVerts * sizeof(CustomVertex),
        D3DUSAGE_WRITEONLY, 0,
        D3DPOOL_DEFAULT, &m_vBuffer[i], NULL )); 
    //Floor
    GenerateSide(m_vBuffer[0],  CustomVertex(-1.0f, -1, 1.0f, 0,1,0, 0,0), 
                                CustomVertex( 1.0f, -1,-1.0f, 0,1,0, 1,1), 1.0f, 0.0f, 1.0f, 1);
    //roof
    GenerateSide(m_vBuffer[1],  CustomVertex(-1.0f, +1, 1.0f, 0,1,0, 1,0), 
                                CustomVertex( 1.0f, +1,-1.0f, 0,1,0, 0,1), 1.0f, 0.0f, 1.0f, 0);
    //side0
    GenerateSide(m_vBuffer[2],  CustomVertex( 1.0f, +1,  1.0f, 0,1,0, 0,0), 
                                CustomVertex( 1.0f, -1, -1.0f, 0,1,0, 1,1), 0.0f, 1.0f, 1.0f, 0);
    //side1
    GenerateSide(m_vBuffer[3],  CustomVertex( -1.0f, -1, -1.0f, 0,1,0, 1,1), 
                                CustomVertex( 1.0f, +1, -1.0f, 0,1,0, 0,0), 1.0f, 1.0f, 0.0f, 1);
    //side2
    GenerateSide(m_vBuffer[4],  CustomVertex( -1.0f, +1, -1.0f, 0,1,0, 0,0), 
                                CustomVertex( -1.0f, -1,  1.0f, 0,1,0, 1,1), 0.0f, 1.0f, 1.0f, 0);
    //side3
    GenerateSide(m_vBuffer[5],  CustomVertex( -1.0f, +1, 1.0f, 0,1,0, 0,0), 
                                CustomVertex( 1.0f, -1, 1.0f, 0,1,0, 1,1), 1.0f, 1.0f, 0.0f, 1);
}
void SkyBox::InitializeBox( int scaleX,int scaleY,int scaleZ,
    float posX,  float posY,  float posZ)
{
    m_scale[0] = scaleX;m_scale[1] = scaleY;m_scale[2] = scaleZ;
    m_pos[0] = posX; m_pos[1] = posY; m_pos[2] = posZ;
    m_numVerts = 6;
    //create a vertex buffer on GPU
    //for(int i = 0; i < 0; ++i)
    //{
    //    TEST(Engine::Instance()->GetDevice()->CreateVertexBuffer( 6 * sizeof(CustomVertex),
    //        D3DUSAGE_WRITEONLY, 0,
    //        D3DPOOL_DEFAULT , &m_vBuffer[i], NULL ));
    //}
    //CreateFloor();
    //CreateRoof();
    //CreateSide0();
    //CreateSide1();
    //CreateSide2();
    //CreateSide3();
}
void SkyBox::Render(ID3DXEffect* effect)
{
    D3DXMATRIXA16 world;
    D3DXMatrixIdentity(&world);
    D3DXMatrixTranslation(&world, m_pos[0],m_pos[1],m_pos[2]);
    //get the graphical scale
    D3DXMATRIXA16 scale, worldView;
    D3DXMatrixIdentity(&scale);
    D3DXMatrixIdentity(&worldView);
    D3DXMatrixScaling(&scale,  (float)m_scale[0], (float)m_scale[1], (float)m_scale[2]);
    world = scale*world;
    //store the world view
    TEST( effect->SetMatrix( "g_mWorld", &world ) );
    TEST( effect->SetMatrix( "g_mView", &VIEW_MATRIX ) );
    for(int i = 0; i < 6; ++i)
    {
        UINT passes = 0;
        TEST(Engine::Instance()->GetDevice()->SetVertexDeclaration(CustomVertex::s_dcl));
        TEST(Engine::Instance()->GetDevice()->SetStreamSource( 0, m_vBuffer[i] , 0, sizeof( CustomVertex ) ));

        TEST(effect->Begin( &passes, 0 ));
        if(m_texture[i])
            TEST(effect->SetTexture("Diffuse", m_texture[i]));

        for(unsigned int  iPass = 0; iPass < passes; iPass++ )
        {
            TEST(effect->BeginPass( iPass ));

            TEST(Engine::Instance()->GetDevice()->DrawPrimitive(D3DPT_TRIANGLELIST, 0, (m_numVerts / 3) ));

            TEST(effect->EndPass());
        }
        TEST(effect->End());
    }
}
void SkyBox::CreateFloor()
{
    //Generate the FLOOR nodes
    CustomVertex* vertexArray = new CustomVertex[6];
    //0 the data
    memset(vertexArray,0, sizeof(CustomVertex) * 6);
    vertexArray[0] = CustomVertex(-1.0f, -1, 1.0f, 0,1,0, 0,0);// Top left
    vertexArray[1] = CustomVertex( 1.0f, -1, 1.0f, 0,1,0, 1,0); //top right
    vertexArray[2] = CustomVertex( 1.0f, -1,-1.0f, 0,1,0, 1,1);  //bottom right
    vertexArray[3] = CustomVertex(-1.0f, -1,-1.0f, 0,1,0, 0,1);  // bottom left
    vertexArray[4] = CustomVertex(-1.0f, -1, 1.0f, 0,1,0, 0,0);// Top left
    vertexArray[5] = CustomVertex( 1.0f, -1,-1.0f, 0,1,0, 1,1);  //bottom right

    VOID* pVertices;

    int BufferSize = sizeof( CustomVertex )* 6;

    m_vBuffer[0]->Lock( 0, BufferSize, ( void** )&pVertices, 0); 

    memcpy( pVertices, vertexArray, BufferSize );

    TEST(m_vBuffer[0]->Unlock());

    delete[] vertexArray;
}
void SkyBox::CreateRoof()
{
    //Generate the ROOF nodes
    CustomVertex* vertexArray = new CustomVertex[6];
    //0 the data
    memset(vertexArray,0, sizeof(CustomVertex) * 6);

    vertexArray[0] = CustomVertex(-1.0f, +1, 1.0f, 0,1,0, 1,0);// Top left
    vertexArray[1] = CustomVertex( 1.0f, +1,-1.0f, 0,1,0, 0,1); //bottom right
    vertexArray[2] = CustomVertex( 1.0f, +1, 1.0f, 0,1,0, 0,0);  //Top Right

    vertexArray[3] = CustomVertex(-1.0f, +1,-1.0f, 0,1,0, 1,1);  // bottom left
    vertexArray[4] = CustomVertex( 1.0f, +1,-1.0f, 0,1,0, 0,1); //bottom right
    vertexArray[5] = CustomVertex(-1.0f, +1, 1.0f, 0,1,0, 1,0);// Top left

    VOID* pVertices;

    int BufferSize = sizeof( CustomVertex )* 6;

    m_vBuffer[1]->Lock( 0, BufferSize, ( void** )&pVertices, 0); 

    memcpy( pVertices, vertexArray, BufferSize );

    TEST(m_vBuffer[1]->Unlock());

    delete[] vertexArray;
}
void SkyBox::CreateSide0()
{
    //Generate the POSITIVE X SIDE
    CustomVertex* vertexArray = new CustomVertex[6];
    //0 the data
    memset(vertexArray,0, sizeof(CustomVertex) * 6);
    vertexArray[0] = CustomVertex( 1.0f, +1,  1.0f, 0,1,0, 0,0);// Top left
    vertexArray[1] = CustomVertex( 1.0f, +1, -1.0f, 0,1,0, 1,0); //top right
    vertexArray[2] = CustomVertex( 1.0f, -1, -1.0f, 0,1,0, 1,1);  //bottom right
    vertexArray[3] = CustomVertex( 1.0f, -1,  1.0f, 0,1,0, 0,1);  // bottom left
    vertexArray[4] = CustomVertex( 1.0f, +1, +1.0f, 0,1,0, 0,0);// Top left
    vertexArray[5] = CustomVertex( 1.0f, -1, -1.0f, 0,1,0, 1,1);  //bottom right

    VOID* pVertices;

    int BufferSize = sizeof( CustomVertex )* 6;

    m_vBuffer[2]->Lock( 0, BufferSize, ( void** )&pVertices, 0); 

    memcpy( pVertices, vertexArray, BufferSize );

    TEST(m_vBuffer[2]->Unlock());

    delete[] vertexArray;
}
void SkyBox::CreateSide1()
{
    //Generate the NEGATIVE Z SIDE
    CustomVertex* vertexArray = new CustomVertex[6];
    //0 the data
    memset(vertexArray,0, sizeof(CustomVertex) * 6);
    vertexArray[0] = CustomVertex( -1.0f, -1, -1.0f, 0,1,0, 1,1);// bottom right
    vertexArray[1] = CustomVertex(1.0f, +1,  -1.0f, 0,1,0, 0,0 ); //top right
    vertexArray[2] = CustomVertex(-1.0f, +1, -1.0f, 0,1,0, 1,0 );  //top left

    vertexArray[3] = CustomVertex( 1.0f, -1, -1.0f, 0,1,0, 0,1);  // bottom left
    vertexArray[4] = CustomVertex( 1.0f, +1, -1.0f, 0,1,0, 0,0);// bottom right
    vertexArray[5] = CustomVertex(-1.0f, -1, -1.0f, 0,1,0, 1,1 );  // top left

    VOID* pVertices;

    int BufferSize = sizeof( CustomVertex )* 6;

    m_vBuffer[3]->Lock( 0, BufferSize, ( void** )&pVertices, 0); 

    memcpy( pVertices, vertexArray, BufferSize );

    TEST(m_vBuffer[3]->Unlock());

    delete[] vertexArray;
}
void SkyBox::CreateSide2()
{
    //Generate the NEGATIVE X SIDE
    CustomVertex* vertexArray = new CustomVertex[6];
    //0 the data

    memset(vertexArray,0, sizeof(CustomVertex) * 6);
    vertexArray[0] = CustomVertex( -1.0f, +1,  1.0f, 0,1,0, 1,0);// Top left
    vertexArray[1] = CustomVertex( -1.0f, -1, -1.0f, 0,1,0, 0,1); // bottom right
    vertexArray[2] = CustomVertex( -1.0f, +1, -1.0f, 0,1,0, 0,0);  //top right

    vertexArray[3] = CustomVertex( -1.0f, -1,  1.0f, 0,1,0, 1,1);   // bottom left
    vertexArray[4] = CustomVertex( -1.0f, -1, -1.0f, 0,1,0, 0,1);   // botttom right
    vertexArray[5] = CustomVertex( -1.0f, +1, +1.0f, 0,1,0, 1,0 );  // top left

    VOID* pVertices;

    int BufferSize = sizeof( CustomVertex )* 6;

    m_vBuffer[4]->Lock( 0, BufferSize, ( void** )&pVertices, 0); 

    memcpy( pVertices, vertexArray, BufferSize );

    TEST(m_vBuffer[4]->Unlock());

    delete[] vertexArray;
}
void SkyBox::CreateSide3()
{
    //Generate the POSITIVE Z SIDE
    CustomVertex* vertexArray = new CustomVertex[6];
    //0 the data
    memset(vertexArray,0, sizeof(CustomVertex) * 6);
    vertexArray[0] = CustomVertex( -1.0f, -1, 1.0f, 0,1,0, 0,1);// bottom right
    vertexArray[1] = CustomVertex( -1.0f, +1, 1.0f, 0,1,0, 0,0); //top right
    vertexArray[2] = CustomVertex( 1.0f, +1,  1.0f, 0,1,0, 1,0);  //top left

    vertexArray[3] = CustomVertex( 1.0f, -1, 1.0f, 0,1,0, 1,1);  // bottom left
    vertexArray[4] = CustomVertex(-1.0f, -1, 1.0f, 0,1,0, 0,1 );// bottom right
    vertexArray[5] = CustomVertex( 1.0f, +1, 1.0f, 0,1,0, 1,0);  // top left

    VOID* pVertices;

    int BufferSize = sizeof( CustomVertex )* 6;

    m_vBuffer[5]->Lock( 0, BufferSize, ( void** )&pVertices, 0); 

    memcpy( pVertices, vertexArray, BufferSize );

    TEST(m_vBuffer[5]->Unlock());

    delete[] vertexArray;
}
void SkyBox::GenerateSide( LPDIRECT3DVERTEXBUFFER9 buffer, CustomVertex& start, 
    CustomVertex& finish, float x_mul,float y_mul,float z_mul,int winding)
{
    const int tempVerts =  SKYBOX_RES * SKYBOX_RES;
    CustomVertex* vertexArray = new CustomVertex[tempVerts];
    memset(vertexArray,0, sizeof(CustomVertex) * tempVerts);
    CustomVertex currentVertex = start;
    D3DXVECTOR4 posDif( finish.pos.x - start.pos.x,
                        finish.pos.y - start.pos.y,
                        finish.pos.z - start.pos.z, 0);
    D3DXVECTOR2 uvDif(  finish.texCoord.x - start.texCoord.x,
                        finish.texCoord.y - start.texCoord.y);

    float inv = (1.0f / ((float)SKYBOX_RES - 1));
    posDif.x *= x_mul * inv;
    posDif.y *= y_mul * inv;
    posDif.z *= z_mul * inv;
    uvDif.x *= inv;
    uvDif.y *= inv;

    int currentIndex = 0;
    for(int i = 0; i < SKYBOX_RES; ++i)
    {
        for(int j = 0; j < SKYBOX_RES; ++j)
        {
            //copy data
            vertexArray[currentIndex] = currentVertex;
            //adjsut position
            currentVertex.pos.x += posDif.x;
            if(posDif.x <= 0.0f)
            {
                currentVertex.pos.y += posDif.y;
                currentVertex.texCoord.y += uvDif.y;
            }
            else
                currentVertex.texCoord.x += uvDif.x;

            currentIndex++;
        }
        
        //adjust positions
        currentVertex.pos.z += posDif.z;            
        currentVertex.pos.x = start.pos.x;
        if(posDif.x <= 0.0f)
        {
            currentVertex.texCoord.x += uvDif.x;
            currentVertex.texCoord.y = start.texCoord.y;
            currentVertex.pos.y = start.pos.y;
        }
        else
        {
            currentVertex.texCoord.y += uvDif.y;
            currentVertex.texCoord.x = start.texCoord.x;
            currentVertex.pos.y += posDif.y;
        }
    }
    for(int i = 0; i < tempVerts; ++i)
    {
        D3DXVec4Normalize(&vertexArray[i].pos,&vertexArray[i].pos);
        vertexArray[i].pos.w = 1;
    }
    CustomVertex* triArray = new CustomVertex[m_numVerts];
    memset(triArray,0, sizeof(CustomVertex) * m_numVerts);

    currentIndex = 0;
    for(int j = 0; j < SKYBOX_RES - 1; ++j)
    {
        for(int i = 0;  i < SKYBOX_RES - 1; ++i)
        {
            if(winding > 0)
            {
                //tri 1
                triArray[currentIndex++] = vertexArray[(SKYBOX_RES * j) + i];
                triArray[currentIndex++] = vertexArray[(SKYBOX_RES * j) + i + 1];
                triArray[currentIndex++] = vertexArray[(SKYBOX_RES * j) + i + SKYBOX_RES];
                //tri 2
                triArray[currentIndex++] = vertexArray[(SKYBOX_RES * j) + i + 1];
                triArray[currentIndex++] = vertexArray[(SKYBOX_RES * j) + (i + 1) + SKYBOX_RES];
                triArray[currentIndex++] = vertexArray[(SKYBOX_RES * j) + i + SKYBOX_RES];
            }
            else
            {
                triArray[currentIndex++] = vertexArray[(SKYBOX_RES * j) + i + 1];
                triArray[currentIndex++] = vertexArray[(SKYBOX_RES * j) + i];
                triArray[currentIndex++] = vertexArray[(SKYBOX_RES * j) + i + SKYBOX_RES];
                //tri 2
                triArray[currentIndex++] = vertexArray[(SKYBOX_RES * j) + (i + 1) + SKYBOX_RES];
                triArray[currentIndex++] = vertexArray[(SKYBOX_RES * j) + i + 1];
                triArray[currentIndex++] = vertexArray[(SKYBOX_RES * j) + i + SKYBOX_RES];
            }
        }
    }

    VOID* pVertices;

    int BufferSize = sizeof( CustomVertex )* m_numVerts;

    buffer->Lock( 0, BufferSize, ( void** )&pVertices, 0); 

    memcpy( pVertices, triArray, BufferSize );

    TEST(buffer->Unlock());

    delete[] vertexArray;
    delete[] triArray;
}
